package com.whfc.openapi.api.fim.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.whfc.common.constant.QueueConst;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.util.JSONUtil;
import com.whfc.common.util.RandomUtil;
import com.whfc.fim.dto.FimAlgConfigDTO;
import com.whfc.fim.dto.FimAlgDeviceDTO;
import com.whfc.fim.dto.FimAlgTypeDTO;
import com.whfc.fim.enums.FimDeviceRuleType;
import com.whfc.fim.param.FimAlgResultParam;
import com.whfc.fim.service.FimAlgConfigService;
import com.whfc.fim.service.FimWarnRuleService;
import com.whfc.fvs.dto.FvsDeviceDTO;
import com.whfc.fvs.dto.FvsSnapshotDTO;
import com.whfc.fvs.entity.FvsDevice;
import com.whfc.fvs.entity.FvsSnapshot;
import com.whfc.fvs.service.FvsDeviceService;
import com.whfc.fvs.service.FvsSnapshotService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

/**
 * @author : qzexing
 * @version : 1.0
 * @date : 2021-01-23 17:05
 */
@Service
public class FimAlgResultServiceImpl implements FimAlgResultService {

    private static final Logger logger = LoggerFactory.getLogger(FimAlgResultServiceImpl.class);
    @Autowired
    private AmqpTemplate amqpTemplate;

    /**
     * 算法识别结果图片路径
     */
    private String fimAlgImgPath = "fim/alg/result/img";

    /**
     * 算法识别结果抓拍图片路径
     */
    private String fimSnapshotAlgImgPath = "fim/snapshot/capture";

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private FilePathConfig filePathConfig;

    @DubboReference(interfaceClass = FimWarnRuleService.class, version = "1.0.0")
    private FimWarnRuleService fimWarnRuleService;

    @DubboReference(interfaceClass = FimAlgConfigService.class, version = "1.0.0")
    private FimAlgConfigService fimAlgConfigService;

    @DubboReference(interfaceClass = FvsDeviceService.class, version = "1.0.0")
    private FvsDeviceService fvsDeviceService;

    @DubboReference(interfaceClass = FvsSnapshotService.class, version = "1.0.0")
    private FvsSnapshotService fvsSnapshotService;

    @Override
    public void algResultUpload(FimAlgResultParam fimAlgResultParam) {
        amqpTemplate.convertAndSend(QueueConst.FIM_RESULT, JSONUtil.toString(fimAlgResultParam));
    }

    @Override
    public void algResultUpload(FimAlgResultParam fimAlgResultParam, MultipartFile img) {
        //上传图片
        String imgUrl = uploadImg(img);
        if (StringUtils.isNoneEmpty(imgUrl)) {
            //保存图片地址
            List<String> imgUrlList = new ArrayList<>();
            imgUrlList.add(imgUrl);
            fimAlgResultParam.setAlgResultImgList(imgUrlList);
        }
        //推送数据
        amqpTemplate.convertAndSend(QueueConst.FIM_RESULT, JSONUtil.toString(fimAlgResultParam));
    }

    @Override
    public List<FimAlgConfigDTO> getAlgConfig(Integer deptId) {
        return fimAlgConfigService.list(deptId);
    }

    @Override
    public List<FimAlgTypeDTO> algTypeList(Integer deptId) {
        return fimWarnRuleService.algTypeList(deptId);
    }

    @Override
    public List<FimAlgDeviceDTO> deviceConfigList(Integer deptId) {
        return fimAlgConfigService.deviceConfigList(deptId);
    }

//    {"BehaviorResults": [{"DeviceName": "AOX-C01@HD",
//                          "SerialNumber": "210235C5CX3227000134",
//                          "DeviceAddr0": "192.168.1.30",
//                          "DeviceAddr1": "192.168.2.30",
//                          "ChannelId": "1",
//                          "IPCAddr": "192.168.1.64",
//                          "ChannelName": "\u7403\u673a",
//                          "IPCSerialNum": "iDS-2DE7223FQA-MA20190801CCCHD45687081X",
//                          "AlarmType": 17,
//                          "AlarmId": 3322,
//                          "ReportRate": 0,
//                          "Timestamp": 1667620590,
//                          "BigImageURL": "/alarm/ba/2022-11-05/1_1667620590655_absentdetection_d5faf972-5cbd-11ed-bef4-e4f14c5050dd.jpg",
//                          "LeftTopX": 0,
//                          "LeftTopY": 0,
//                          "RightBtmX": 0,
//                          "RightBtmY": 0,
//                          "PersonNum": 0,
//                          "PlateNo": "",
//                          "AlarmVideoURL": ""
//    }]}
//
    @Override
    public void receiveYuShiData(String body) {
        JSONObject jsonBody = JSONObject.parseObject(body);
        // 报警时间
        JSONArray behaviorResults = jsonBody.getJSONArray("BehaviorResults");
        if (!ObjectUtils.isEmpty(behaviorResults)) {
            setAiWarnInfo(behaviorResults);
        }
        // 人脸抓拍
        JSONArray faceResults = jsonBody.getJSONArray("FaceResults");
        if (!ObjectUtils.isEmpty(faceResults)){
            setAiFaceInfo(faceResults);
        }

    }

    /**
     * 抽烟-9  安全帽-28  反光衣-34 人脸-53
     * @param body
     */
    @Override
    public void receiveKunyunData(String body) {
        Integer deptId = 90;
        Integer deviceId = 217;
        String deviceName = "硬盘录像机";
        String deviceVendor = "kunyun";

        JSONObject jsonBody = JSONObject.parseObject(body);
        // 摄像头id
        String cameraId = jsonBody.getString("cameraId");
        // 报警图片内容 base64
        String alarmPicData = jsonBody.getString("alarmPicData");
        if (alarmPicData==null) {
            logger.info("==========base64图片为空=============");
            return;
        }
        // 图片类型相对路径
        String alarmPicName = jsonBody.getString("alarmPicName");

        Long timestamp = jsonBody.getLong("timestamp");

        Integer taskId = jsonBody.getInteger("taskId");
        logger.info("图片相对路径alarmPicName={},时间timestamp={},报警类型={}",alarmPicName,timestamp,taskId);
        // 抓拍
        if (53==taskId) {
            List<FvsSnapshotDTO> snapshotList = new ArrayList<>();
            //创建快照
            FvsSnapshotDTO fvsSnapshot = new FvsSnapshotDTO();
            fvsSnapshot.setDeptId(deptId);
            fvsSnapshot.setDeviceId(deviceId);
            fvsSnapshot.setDeviceName(deviceName);
            fvsSnapshot.setTime(new Date(timestamp*1000));

            // 上传到oss
            String imgUrl = uploadImg(alarmPicData, fimSnapshotAlgImgPath,alarmPicName);
            fvsSnapshot.setSnapshotUrl(imgUrl);

            snapshotList.add(fvsSnapshot);
            fvsSnapshotService.batchInsert(snapshotList);
            return;
        }
        FimDeviceRuleType ruleKunYun = getRuleKunYun(taskId);
        if (ruleKunYun== null) {
            logger.error("未获取到报警规则taskId={}",taskId);
            return;
        }
        FimAlgResultParam fimAlgResultParam = new FimAlgResultParam();
        fimAlgResultParam.setDeptId(deptId);
        fimAlgResultParam.setDeviceId(deviceId);
        fimAlgResultParam.setDeviceName(deviceName);
        fimAlgResultParam.setDeviceVendor(deviceVendor);
        fimAlgResultParam.setAlgCheckType(ruleKunYun.value());
        fimAlgResultParam.setAlgCheckTypeName(ruleKunYun.detail());
        fimAlgResultParam.setTime(new Date(timestamp*1000));
//        fimAlgResultParam.setBase64(alarmPicData);
        // 图片对象不为空
         // 上传到oss
         String imgUrl = uploadImg(alarmPicData, fimAlgImgPath,alarmPicName);
         List<String> algResultImgList = new ArrayList<>();
         algResultImgList.add(imgUrl);
         fimAlgResultParam.setAlgResultImgList(algResultImgList);


        //推送数据
        amqpTemplate.convertAndSend(QueueConst.FIM_RESULT, JSONUtil.toString(fimAlgResultParam));

    }

    // 抽烟-9  安全帽-28  反光衣-34   人脸-53
    public FimDeviceRuleType getRuleKunYun(Integer value){
        switch (value){
            case 9:
                return FimDeviceRuleType.SMOKING;
            case 28:
                return FimDeviceRuleType.NOHELMET;
            case 34:
                return FimDeviceRuleType.NOREFLECTVEST;
            default:
                return null;

        }
    }

    /**
     * 人脸抓拍上报
     * @param faceResults
     */
    private void setAiFaceInfo(JSONArray faceResults) {
        List<FvsSnapshotDTO> snapshotList = new ArrayList<>();
        for (Object faceResult : faceResults) {
            JSONObject jsonObject = JSONObject.parseObject(faceResult.toString());
            // 设备序列号 唯一标识
            String ipcSerialNum = jsonObject.getString("IPCSerialNum");

            FvsDeviceDTO fvsDevice = fvsDeviceService.selectBySn(ipcSerialNum);
            if (fvsDevice==null) {
                logger.error("未获取到摄像头设备信息,ipcSerialNum:{}",ipcSerialNum);
                continue;
            }

            Long timestamp = jsonObject.getLong("Timestamp");

            //创建快照
            FvsSnapshotDTO fvsSnapshot = new FvsSnapshotDTO();
            fvsSnapshot.setDeptId(fvsDevice.getDeptId());
            fvsSnapshot.setDeviceId(fvsDevice.getId());
            fvsSnapshot.setDeviceName(fvsDevice.getName());
            fvsSnapshot.setTime(new Date(timestamp*1000));
            // 图片对象不为空
            if (!ObjectUtils.isEmpty(jsonObject.get("BigImage"))) {
                // 图片类型相对路径
                String bigImageURL = jsonObject.getString("BigImageURL");
                // 取出base64
                JSONObject bigImage = JSONObject.parseObject(jsonObject.get("BigImage").toString());
                // Base64图片
                String imageBase64 = bigImage.getString("Image");
                // 上传到oss
                String imgUrl = uploadImg(imageBase64, fimSnapshotAlgImgPath,bigImageURL);
                fvsSnapshot.setSnapshotUrl(imgUrl);
            }
            snapshotList.add(fvsSnapshot);
        }
        if (snapshotList.size()>0) {
            fvsSnapshotService.batchInsert(snapshotList);
        }
    }

    /**
     * 算法报警上报
     * @param behaviorResults
     */
    private void setAiWarnInfo(JSONArray behaviorResults) {
        List<String> algResultImgList = new ArrayList<>();
        for (Object behaviorResult : behaviorResults) {
            JSONObject jsonObject = JSONObject.parseObject(behaviorResult.toString());
            // 设备序列号 唯一标识
            String ipcSerialNum = jsonObject.getString("IPCSerialNum");

            FvsDeviceDTO fvsDevice = fvsDeviceService.selectBySn(ipcSerialNum);
            if (fvsDevice==null) {
                logger.error("未获取到摄像头设备信息,ipcSerialNum:{}",ipcSerialNum);
                continue;
            }
            // 报警类型
            Integer alarmType = jsonObject.getInteger("AlarmType");
            Integer valueType = jsonObject.getInteger("ValueType");
            FimDeviceRuleType rule = getRule(alarmType,valueType);
            if (rule ==null) {
                logger.error("未获取到报警规则alarmType={},valueType={}",alarmType,valueType);
                continue;
            }
            Long timestamp = jsonObject.getLong("Timestamp");

            FimAlgResultParam fimAlgResultParam = new FimAlgResultParam();
            fimAlgResultParam.setDeptId(fvsDevice.getDeptId());
            fimAlgResultParam.setDeviceId(fvsDevice.getId());
            fimAlgResultParam.setDeviceName(fvsDevice.getName());
            fimAlgResultParam.setDeviceVendor(fvsDevice.getVendor());
            fimAlgResultParam.setAlgCheckType(rule.value());
            fimAlgResultParam.setAlgCheckTypeName(rule.detail());
            fimAlgResultParam.setTime(new Date(timestamp*1000));
            // 图片对象不为空
            if (!ObjectUtils.isEmpty(jsonObject.get("BigImage"))) {
                // 图片类型相对路径
                String bigImageURL = jsonObject.getString("BigImageURL");
                // 取出base64
                JSONObject bigImage = JSONObject.parseObject(jsonObject.get("BigImage").toString());
                // Base64图片
                String imageBase64 = bigImage.getString("Image");
                // 上传到oss
                String imgUrl = uploadImg(imageBase64, fimAlgImgPath,bigImageURL);
                algResultImgList = new ArrayList<>();
                algResultImgList.add(imgUrl);
                fimAlgResultParam.setAlgResultImgList(algResultImgList);
            }

            //推送数据
            amqpTemplate.convertAndSend(QueueConst.FIM_RESULT, JSONUtil.toString(fimAlgResultParam));
        }
    }

    /**
     * base64转化成 inputStream
     *
     * @param base64
     * @return
     */
    public static InputStream base64ToInputStream(String base64) {
        ByteArrayInputStream stream = null;
        try {
            byte[] bytes = Base64.getDecoder().decode(base64);
            stream = new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stream;
    }


    @Test
    public void receiveYuShiData(){
        String s = "{\"BehaviorResults\": [{\"DeviceName\": \"AOX-C01@HD\", \"SerialNumber\": \"210235C5CX3227000134\", \"DeviceAddr0\": \"192.168.1.30\", \"DeviceAddr1\": \"192.168.2.30\", \"ChannelId\": \"1\", \"IPCAddr\": \"192.168.1.64\", \"ChannelName\": \"\\u7403\\u673a\", \"IPCSerialNum\": \"111\", \"AlarmType\": 17, \"AlarmId\": 3322, \"ReportRate\": 0, \"Timestamp\": 1667620590, \"BigImageURL\": \"/alarm/ba/2022-11-05/1_1667620590655_absentdetection_d5faf972-5cbd-11ed-bef4-e4f14c5050dd.jpg\", \"LeftTopX\": 0, \"LeftTopY\": 0, \"RightBtmX\": 0, \"RightBtmY\": 0, \"PersonNum\": 0, \"PlateNo\": \"\", \"AlarmVideoURL\": \"\"}]}";
        this.receiveYuShiData(s);
    }
    //4: 未戴安全帽 --- 10
    //5: 未穿工服   --- 280
    //6: 打电话检测 ---130
    //7: 吸烟检测   --- 120
    //8: 明火/烟雾检测
        //当 AlarmType 为 8 时，有此字段
        //ValueType 为 1 时，代表明火检测； --- 90
        //ValueType 为 2 时，代表烟雾检测； ---140
    //17: 离岗检测 ---60
    //20: 区域入侵 ---150
    //21: 电动车禁入 ---160
    //22: 车辆违停占用（消防车通道占用） ---170
    //16: 睡岗检测  ---180
    //18: 逃生通道堵塞 ---190
    //62: 跌倒检测 ---50
    //19: 物品遗失 ---200
    //33: 口罩检测 ---210
    //35：区域人数统计 ---220
    //45: 绊线统计 ---230
    //63：人员数量超限 --- 40
    //65：反光衣/带检测 ---20
    //89：攀高 ---240
    //57：人员逗留 ---250
    //91：人员聚集 ---260
    //46：剧烈运动 ---270
    public FimDeviceRuleType getRule(Integer value,Integer valueType){
        switch (value){
            case 4:
                return FimDeviceRuleType.NOHELMET;
            case 5:
                return FimDeviceRuleType.UNIFORM;
            case 6:
                return FimDeviceRuleType.PLAYING_PHONE;
            case 7:
                return FimDeviceRuleType.SMOKING;
            case 8:
                if (valueType==1){
                    return FimDeviceRuleType.FIRE;
                }else {
                    return FimDeviceRuleType.SMOG;
                }
            case 16:
                return FimDeviceRuleType.SLEEP_POST;
            case 17:
                return FimDeviceRuleType.PERSONOUT;
            case 18:
                return FimDeviceRuleType.ESCAPE_WAY_JAM;
            case 19:
                return FimDeviceRuleType.ITEM_LOSE;
            case 20:
                return FimDeviceRuleType.AREA_INVADE;
            case 21:
                return FimDeviceRuleType.ELECTROCAR;
            case 22:
                return FimDeviceRuleType.STOPPED_VEHICLE;
            case 33:
                return FimDeviceRuleType.MASK;
            case 35:
                return FimDeviceRuleType.AREA_PEOPLE_NUM;
            case 45:
                return FimDeviceRuleType.BANXIAN_PEOPLE_NUM;
            case 46:
                return FimDeviceRuleType.ACUTE_MOTION;
            case 57:
                return FimDeviceRuleType.PEOPLE_STAY;
            case 62:
                return FimDeviceRuleType.PERSONFALL;
            case 63:
                return FimDeviceRuleType.PERSONFOCUS;
            case 65:
                return FimDeviceRuleType.NOREFLECTVEST;
            case 89:
                return FimDeviceRuleType.CLIMB;
            case 91:
                return FimDeviceRuleType.PEOPLE_GATHER;
            default:
                return null;

        }
    }

    private String uploadImg(MultipartFile img) {
        if (img == null) {
            return null;
        }
        try {
            String fileName = RandomUtil.getRandomFileName() + ".png";
            String ossKey = filePathConfig.getFilePath(fimAlgImgPath, fileName);
            return fileHandler.upload(ossKey, img.getInputStream());
        } catch (IOException e) {
            return null;
        }
    }

    private String uploadImg(String base64,String path,String fileName) {
        try {
            InputStream inputStream = base64ToInputStream(base64);
            if (inputStream == null) {
                return null;
            }
            String ossKey = filePathConfig.getFilePath(path, fileName);
            return fileHandler.upload(ossKey, inputStream);
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("上传失败");
        }
        return "";
    }
}
